home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 16 / Example 16.1 / mapObject.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-17  |  8.0 KB  |  324 lines

  1. #include "mapObject.h"
  2. #include "unit.h"
  3. #include "building.h"
  4. #include "groupAi.h"
  5.  
  6. //Line interface to draw selected units/buildings with
  7. ID3DXLine *line = NULL;
  8.  
  9. //variables used for fog-of-war
  10. IDirect3DTexture9* sightTexture = NULL;
  11. ID3DXMesh *sightMesh = NULL;
  12. D3DMATERIAL9 sightMtrl;
  13. EFFECT_SELECTED *selectedEffect = NULL;
  14.  
  15. struct SIGHTVertex
  16. {
  17.     SIGHTVertex(){}
  18.     SIGHTVertex(D3DXVECTOR3 pos, D3DXVECTOR2 _uv)
  19.     {
  20.         position = pos;
  21.         uv = _uv;
  22.     }
  23.  
  24.     D3DXVECTOR3 position;
  25.     D3DXVECTOR2 uv;
  26.  
  27.     static const DWORD FVF;
  28. };
  29.  
  30. const DWORD SIGHTVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
  31.  
  32. void LoadMapObjectResources(IDirect3DDevice9* m_pDevice)
  33. {
  34.     D3DXCreateLine(m_pDevice, &line);
  35.  
  36.     //Sight texture
  37.     m_pDevice->CreateTexture(64, 64, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &sightTexture, NULL);
  38.  
  39.     D3DLOCKED_RECT sRect;
  40.     sightTexture->LockRect(0, &sRect, NULL, NULL);
  41.     BYTE *bytes = (BYTE*)sRect.pBits;
  42.     memset(bytes, 0, sRect.Pitch*sRect.Pitch);
  43.     
  44.     float intensity = 1.3f;
  45.     D3DXVECTOR2 center = D3DXVECTOR2(32.0f, 32.0f);
  46.     
  47.     for(int y=0;y<64;y++)
  48.         for(int x=0;x<64;x++)
  49.         {                        
  50.             float d = D3DXVec2Length(&(center - D3DXVECTOR2(x,y)));
  51.             int value = ((32.0f - d) / 32.0f) * 255.0f * intensity;
  52.             if(value < 0)value = 0;
  53.             if(value > 255)value = 255;
  54.             bytes[x + y * sRect.Pitch] = value;
  55.         }
  56.     sightTexture->UnlockRect(0);
  57.  
  58.     //D3DXSaveTextureToFile("sightTexture.bmp", D3DXIFF_BMP, sightTexture, NULL);
  59.  
  60.     //Calculate sight mesh (a simple quad)
  61.     D3DXCreateMeshFVF(2, 4, D3DXMESH_MANAGED, SIGHTVertex::FVF, m_pDevice, &sightMesh);
  62.  
  63.     //Create 4 vertices
  64.     SIGHTVertex* v = 0;
  65.     sightMesh->LockVertexBuffer(0,(void**)&v);
  66.     v[0] = SIGHTVertex(D3DXVECTOR3(-1, 0, 1),  D3DXVECTOR2(0, 0));
  67.     v[1] = SIGHTVertex(D3DXVECTOR3( 1, 0, 1),  D3DXVECTOR2(1, 0));
  68.     v[2] = SIGHTVertex(D3DXVECTOR3(-1, 0, -1), D3DXVECTOR2(0, 1));
  69.     v[3] = SIGHTVertex(D3DXVECTOR3( 1, 0, -1), D3DXVECTOR2(1, 1));
  70.     sightMesh->UnlockVertexBuffer();
  71.  
  72.     //Create 2 faces
  73.     WORD* indices = 0;
  74.     sightMesh->LockIndexBuffer(0,(void**)&indices);    
  75.     indices[0] = 0; indices[1] = 1; indices[2] = 2;
  76.     indices[3] = 1; indices[4] = 3; indices[5] = 2;
  77.     sightMesh->UnlockIndexBuffer();
  78.  
  79.     //Set Attributes for the 2 faces
  80.     DWORD *att = 0;
  81.     sightMesh->LockAttributeBuffer(0,&att);
  82.     att[0] = 0; att[1] = 0;
  83.     sightMesh->UnlockAttributeBuffer();
  84.  
  85.     //Sight MTRL
  86.     memset(&sightMtrl, 0, sizeof(D3DMATERIAL9));
  87.     sightMtrl.Diffuse = sightMtrl.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
  88.  
  89.     //Selected Effect
  90.     selectedEffect = new EFFECT_SELECTED(m_pDevice);
  91. }
  92.  
  93. void UnloadMapObjectResources()
  94. {
  95.     if(line)line->Release();
  96.     line = NULL;
  97.  
  98.     if(sightTexture)sightTexture->Release();
  99.     sightTexture = NULL;
  100.  
  101.     if(sightMesh)sightMesh->Release();
  102.     sightMesh = NULL;
  103. }
  104.  
  105. INTPOINT GetScreenPos(D3DXVECTOR3 pos, IDirect3DDevice9* m_pDevice)
  106. {
  107.     D3DXVECTOR3 screenPos;
  108.     D3DVIEWPORT9 Viewport;
  109.     D3DXMATRIX Projection, View, World;
  110.  
  111.     m_pDevice->GetViewport(&Viewport);
  112.     m_pDevice->GetTransform(D3DTS_VIEW, &View);
  113.     m_pDevice->GetTransform(D3DTS_PROJECTION, &Projection);
  114.     D3DXMatrixIdentity(&World);
  115.     D3DXVec3Project(&screenPos, &pos, &Viewport, &Projection, &View, &World);
  116.  
  117.     return INTPOINT(screenPos.x, screenPos.y);
  118. }
  119.  
  120. //////////////////////////////////////////////////////////////////////////////////
  121. //                                MapObject                                        //
  122. //////////////////////////////////////////////////////////////////////////////////
  123.  
  124. MAPOBJECT::MAPOBJECT()
  125. {
  126.     //Sets all variables to 0, NULL or False
  127.     m_isBuilding = false;
  128.     m_pTerrain = NULL;
  129.     m_hp = m_hpMax = 0;
  130.     m_range = m_damage = 0;
  131.     m_sightRadius = 0.0f;
  132.     m_team = m_type = 0;
  133.     m_selected = m_dead = m_visible = false;
  134.     m_pTarget = NULL;
  135.     m_pDevice = NULL;
  136.     m_pGroup = NULL;
  137.     m_groupNumber = -1;
  138. }
  139.  
  140. RECT MAPOBJECT::GetMapRect(int border)
  141. {
  142.     if(border < 0)border = 0;
  143.  
  144.     RECT mr = {m_mappos.x - border, 
  145.                m_mappos.y - border,
  146.                m_mappos.x + m_mapsize.x + border,
  147.                m_mappos.y + m_mapsize.y + border};
  148.  
  149.     //Clip Rectangle to Terrain border
  150.     if(m_pTerrain != NULL)
  151.     {
  152.         if(mr.left < 0)mr.left = 0;
  153.         if(mr.right >= m_pTerrain->m_size.x)mr.right = m_pTerrain->m_size.x - 1;
  154.         if(mr.top < 0)mr.top = 0;
  155.         if(mr.bottom >= m_pTerrain->m_size.y)mr.bottom = m_pTerrain->m_size.y - 1;
  156.     }
  157.  
  158.     return mr;
  159. }
  160.  
  161. INTPOINT MAPOBJECT::GetAttackPos(INTPOINT from)
  162. {
  163.     try
  164.     {
  165.         if(m_pTerrain == NULL || !m_pTerrain->Within(m_mappos))return INTPOINT(-1, -1);
  166.  
  167.         RECT r = GetMapRect(1);
  168.         RECT mr = GetMapRect(0);
  169.  
  170.         INTPOINT bestDest(-1, -1);
  171.         float dist = 10000.0f;
  172.  
  173.         int loop = 0;
  174.  
  175.         //Find the closest available attacking position
  176.         for(int y=r.top;y<=r.bottom;y++)
  177.             for(int x=r.left;x<=r.right;x++)
  178.             {
  179.                 INTPOINT p(x, y);
  180.  
  181.                 if(!p.inRect(mr))        
  182.                 {
  183.                     MAPTILE *tile = m_pTerrain->GetTile(p);
  184.                     float d = from.Distance(p);
  185.  
  186.                     if(tile != NULL && tile->m_pMapObject == NULL && d < dist)
  187.                     {
  188.                         dist = d;
  189.                         bestDest = p;
  190.                     }
  191.                 }
  192.  
  193.                 if(loop++ > 1000)
  194.                 {
  195.                     debug.Print("Loop > 1000, MAPOBJECT::GetAttackPos()");
  196.                     debug << "R Left: " << r.left << ", Right: " << r.right << ", Top: " << r.top << ", Bottom: " << r.bottom << "\n";
  197.                     debug << "Mappos: " << m_mappos.x << ", " << m_mappos.y << "\n";
  198.                     return INTPOINT(-1, -1);
  199.                 }
  200.             }
  201.  
  202.         return bestDest;
  203.     }
  204.     catch(...)
  205.     {
  206.         return INTPOINT(-1, -1);
  207.     }
  208. }
  209.  
  210. void MAPOBJECT::PaintSelected(float time)
  211. {
  212.     if(m_isBuilding)
  213.     {
  214.         BUILDING *build = (BUILDING*)this;        
  215.         if(build->m_training)
  216.             build->m_pTrainingEffect->Render();
  217.     }
  218.  
  219.     if(!m_selected || !selectedEffect)return;
  220.  
  221.     if(!m_isBuilding)
  222.     {
  223.         selectedEffect->Set(m_hp / (float)m_hpMax, 
  224.                             m_position + D3DXVECTOR3(0.0f, 0.2f, 0.0f),
  225.                             time, 
  226.                             1.2f);
  227.     }
  228.     else
  229.     {
  230.         selectedEffect->Set(m_hp / (float)m_hpMax, 
  231.                             m_position + D3DXVECTOR3(0.0f, 1.2f, 0.0f),
  232.                             time, 
  233.                             m_mapsize.x + m_mapsize.y + 2.0f);
  234.     }
  235.  
  236.     selectedEffect->Render();
  237. }
  238.  
  239. void MAPOBJECT::RenderSightMesh()
  240. {
  241.     if(m_pDevice == NULL || sightTexture == NULL || sightMesh == NULL)return;
  242.  
  243.     //Set world transformation matrix
  244.     D3DXMATRIX world, pos, sca;
  245.  
  246.     //Position the mesh at the center of the map object
  247.     D3DXMatrixTranslation(&pos, m_position.x, m_position.y, m_position.z);
  248.  
  249.     //Scale the mesh to the sight radius of the mapobject (XZ plane)
  250.     D3DXMatrixScaling(&sca, m_sightRadius, 1.0f, m_sightRadius);
  251.  
  252.     D3DXMatrixMultiply(&world, &sca, &pos);
  253.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  254.  
  255.     //Set texture and material
  256.     m_pDevice->SetTexture(0, sightTexture);
  257.     m_pDevice->SetMaterial(&sightMtrl);
  258.  
  259.     //Draw the sight mesh
  260.     sightMesh->DrawSubset(0);
  261. }
  262.  
  263. std::vector<MAPOBJECT*> MAPOBJECT::GetTargetsWithinRange(int theRange)
  264. {
  265.     std::vector<MAPOBJECT*> enemies;
  266.  
  267.     try
  268.     {
  269.         if(m_pTerrain == NULL)return enemies;
  270.  
  271.         RECT r = GetMapRect(theRange);
  272.  
  273.         for(int y=r.top;y<=r.bottom;y++)
  274.             for(int x=r.left;x<=r.right;x++)
  275.             {
  276.                 MAPTILE *tile = m_pTerrain->GetTile(x, y);
  277.  
  278.                 if(tile != NULL && tile->m_pMapObject != NULL)
  279.                     if(tile->m_pMapObject->m_team != m_team && !tile->m_pMapObject->m_dead)
  280.                         if(m_mappos.Distance(INTPOINT(x, y)) <= theRange || m_isBuilding)
  281.                             enemies.push_back(tile->m_pMapObject);
  282.             }
  283.     }
  284.     catch(...)
  285.     {
  286.         debug.Print("Error in MAPOBJECT::GetTargetsWithinRange()");
  287.     }
  288.  
  289.     return enemies;
  290. }
  291.  
  292. MAPOBJECT* MAPOBJECT::BestTargetToAttack(std::vector<MAPOBJECT*> &enemies)
  293. {
  294.     if(enemies.empty())return NULL;
  295.  
  296.     int lowestCost = 10000;
  297.     MAPOBJECT *bestTarget = NULL;
  298.  
  299.     try
  300.     {
  301.         for(int i=0;i<enemies.size();i++)
  302.             if(enemies[i] != NULL && !enemies[i]->m_dead)
  303.             {
  304.                 INTPOINT attackPos = enemies[i]->GetAttackPos(m_mappos);
  305.  
  306.                 if(m_pTerrain->Within(attackPos) && m_pTerrain->PositionAccessible(this, attackPos))
  307.                 {
  308.                     int cost = enemies[i]->m_hp + m_mappos.Distance(enemies[i]->m_mappos) * 30;
  309.  
  310.                     if(cost < lowestCost)
  311.                     {
  312.                         bestTarget = enemies[i];
  313.                         lowestCost = cost;
  314.                     }
  315.                 }
  316.             }
  317.     }
  318.     catch(...)
  319.     {
  320.         debug.Print("Error in MAPOBJECT::BestTargetToAttack()");
  321.     }
  322.  
  323.     return bestTarget;
  324. }